#include<iostream>
#include<string>
#include<vector>
#include<cassert>
#include<cstring>
using  std::cout; 
using  std::endl; 
using  std::cin; 

#include<unistd.h>
#include<sys/wait.h>
#include<sys/types.h>

#include"task.hpp"

int gnum=5;//表示要创建子进程的数量
Task t;//定义任务

struct EndPoint//管理子进程和管道文件
{
    int _child_id;
    int _write_fd;
    std::string processname;
    EndPoint(int child_id,int write_fd)
        :_child_id(child_id)
        ,_write_fd(write_fd)
    {
        char namebuffer[64]={0};
        snprintf(namebuffer,sizeof(namebuffer),"processname-%d[%d:%d]",number++,_child_id,_write_fd);
        processname=namebuffer;
    }

    std::string name()
    {
        return processname;
    }

private:
    static int number;
};
int EndPoint::number=0;


void WaitCommand()
{
    while(true)
    {
        int command=0;
        int n=read(0,&command,sizeof(int));
        //cout<<"void WaitCommand():"<<getpid()<<endl;
        if(n>0)
        {
            //执行任务
            cout<<"flag"<<endl;
            t.Execute(command);
        }
        else if(n==0)
        {
            cout<<"父进程让我退出，我就退出了："<<getpid()<<endl;
            break;
        }
        else
        {
            perror("读取文件异常！");
            break;
        }
    }
}


void CreateProcess(std::vector<EndPoint>& end_points)
{
    std::vector<int>fds;
    for(int i=0;i<gnum;++i)
    {
        //1.1.创建管道文件
        int pipefd[2]={0};
        int ret=pipe(pipefd);
        if(ret!=0)
        {
            perror("创建管道错误！");
            exit(1);
        }
        //1.2.创建子进程
        pid_t id=fork();
        if(id==0)
        {
            //子进程

            //关闭之间进程管道的写端
            for(auto& fd:fds)
            {
                close(fd);
            }

            //1.3. 关闭不需要的fd
            close(pipefd[1]);
            //输入重定向，为了不用管理子进程pipefd[0]的值
            dup2(pipefd[0],0);
            //1.4. 读取信息，并执行任务
            WaitCommand();

            close(pipefd[0]);
            exit(0);
        }
        //父进程

        //1.3. 关闭不需要的fd
        close(pipefd[0]);

        //记入写端的fd
        fds.push_back(pipefd[1]);
        //记入子进程和管道文件之间的关系
        end_points.push_back(EndPoint(id,pipefd[1]));
    }
}

int ShowBorad()
{
    int command=0;
    cout<<"********************************"<<endl;
    cout<<"*0.打印日志任务 1. 数据库处理任务*"<<endl;
    cout<<"*2.资源请求任务 3. 退出程序     *"<<endl;
    cout<<"********************************"<<endl;
    cout<<"请选择：";
    cin>>command;
    return command;

}

void CtrlProcess(std::vector<EndPoint>& end_points)
{
    int cnt=0;
    // 2.1 我们可以写成自动化的，也可以搞成交互式的
    while(true)
    {
        //1.选择任务
        int command=ShowBorad();
        if(command==3)break;
        if(!(command>=0&&command<=2))continue;

        //2. 选择子进程
        int index=cnt++;
        index%=end_points.size();
        std::string name=end_points[index].name();
        cout<<"选择了进程："<<name<<"|处理的任务："<<command<<endl;
        //3. 下发任务给子进程
        write(end_points[index]._write_fd,&command,sizeof(command));

        sleep(1);
    }
}

void WaitProcess(std::vector<EndPoint>& end_points)
{
    // 1. 我们需要让子进程全部退出 --- 只需要让父进程关闭所有的write fd就可以了！
    for(int i=0;i<end_points.size();++i)
    {
        cout<<"父进程让子进程退出："<<end_points[i]._child_id<<endl;
        close(end_points[i]._write_fd);

        waitpid(end_points[i]._child_id,nullptr,0);
        cout<<"父进程回收了子进程："<<end_points[i]._child_id<<endl;
    }
    sleep(5);
}

int main()
{
    std::vector<EndPoint> end_points;
    //1.首先需要创建子进程，并创建对应的管道；
    CreateProcess(end_points);//函数调用结束，我们可以通过end_points得到相应的子进程和管道之间的关系，进而管理它们

    //2.进程间通信，输入对应执行任务指令；
    CtrlProcess(end_points);

    //3.进程退出，回收进程。
    WaitProcess(end_points);

    return 0;
}
